Skip to content

refactor(worker): move integration, chat and ai-agent handler data access into business - #1099

Open
realcodesiman wants to merge 4 commits into
mainfrom
refactor/data-access-worker-integration
Open

refactor(worker): move integration, chat and ai-agent handler data access into business#1099
realcodesiman wants to merge 4 commits into
mainfrom
refactor/data-access-worker-integration

Conversation

@realcodesiman

Copy link
Copy Markdown
Contributor

Summary

  • Removes every direct db.* call from apps/worker/src/{integration,chat,ai-agent,services,lib} (inbound message ingestion, flow steps, template sends, coexist import) per .agents/rules/data-access.md. Bodies are moved verbatim; every isNull TOCTOU guard, sql\col + N`increment, untargetedonConflictDoNothing(), sql.identifier()andwithBlockedOwnerGuard call site is preserved (git diff main | grep withBlockedOwnerGuard` is empty).
  • One of seven parallel scope PRs following feat(contacts): cover full public API for MCP, move logic into business services #1093 (contacts); based on main, append-only barrel edits. The deleteContact handler is left on its main form because feat(contacts): cover full public API for MCP, move logic into business services #1093 already migrates it; expect a keep-both merge in handlers/contact.ts, contact/service.ts, tag/service.ts and the two barrels.

Changes

  • Coexist: coexistSyncRunRepository.{claimRunForSync,incrementProgress,findInitState,findLastSyncedAt,findTerminalCounters,findNewestLiveRunId,findFlushResumeState}, whatsappCoexistStagingRepository.{stagePayload,listUnprocessed,markProcessed,hasUnprocessed}, new coexistImportService holding the historical-import transaction and contactRepository.enrichIfNull (COALESCE SQL verbatim). claimRunForSync deliberately does not filter status IN ('init','running') and takes touchUpdatedAt to preserve the two callers' differing SET clauses.
  • Flow steps: contactService.{setFlowFlags,subscribeBroadcastIfUnsubscribed,unsubscribeBroadcast,setAvatarIfEmpty}, contactNoteService.createFromFlow, tagService.{attachByNamesToContact,listIdsByNames,detachTagIdsFromContact,detachTagFromContacts,linkTagToContactsReturningNew,ensureTagByName,ensureTagChannel,...}, contactSequenceService.{isEnrolled,findFirstActiveStep,findSequenceName}, sequenceDispatchUtils.{findRunning,markCompleted,markCanceled,markFailed}.
  • Chat/inbound: conversationService.{recordInboundActivity,recordOutboundFlowStep,recordOutboundMessageActivity,findByIdWithContact}, inboxService.findWithIntegration{Messenger,Whatsapp}ById, approved-template lookups on the integration services, contactInboxRepository.{findWithContact,findWithConversationAndContact,...}.
  • Libs: flowService.{findActiveById,findAnyActive}, flowVersionService.findByIdForWorkspace, new ai-embedding, integration-lookup and import repositories; lib/db.ts keeps its exported names and signatures.
  • Tests re-pointed to the service boundary plus new regression tests for the TOCTOU guards, the claim predicate, the + N increment and the AI-file enqueue.

Deliberate behavior changes

  1. stepBlockContact now goes through contactService.block (adds findByIdOrFail, contact-info-change events and cache invalidation the raw write lacked).
  2. setFlowFlags now invalidates the contact cache (the raw db.update never did).
  3. process-ai-file enqueues only the embedding ids it just inserted (bulkCreatePending(...).returning), instead of re-reading all rows for the file, which double-enqueued prior runs' embeddings on retry.
  4. send-flow-direct and update-avatar now scope by workspaceId (via contactInboxService.listByContactId / contactService.findById / setAvatarIfEmpty); safe by construction, data is already workspace-scoped upstream.
  5. The inbound/outbound activity conversation UPDATEs add workspaceId to their WHERE via updateFlowStepState.
  6. Plan-location deviations: coexist-import is a business service rather than a database repository; approved-template lookups live on the integration services rather than templateService.

Test plan

  • pnpm --filter @chatbotx.io/database check-types && test
  • pnpm --filter @chatbotx.io/business check-types && test (only the pre-existing ads-conversion-rule.service.test.ts failures remain, also red on main)
  • pnpm --filter worker check-types && test (only the pre-existing flow-import-handler.test.ts failures remain, also red on main)
  • pnpm --filter worker build
  • pnpm lint
  • Staging smoke: inbound WhatsApp message; flow with add-tag + assign-conversation; Messenger template broadcast; enable coexist on a Messenger integration

@github-actions github-actions Bot added the improvement Refactor or performance improvement label Sep 6, 2026
@realcodesiman
realcodesiman force-pushed the refactor/data-access-worker-integration branch from 8f28f45 to 4a27c1a Compare September 9, 2026 00:42
realcodesiman and others added 4 commits September 9, 2026 07:43
…cess into business

Removes direct db usage from apps/worker/src/{integration,chat,ai-agent,
services,lib} per .agents/rules/data-access.md. Hot-path bodies are
moved verbatim; every isNull TOCTOU guard, sql increment, untargeted
onConflictDoNothing, sql.identifier and withBlockedOwnerGuard call site
is preserved.

- coexist: claimRunForSync/incrementProgress/findInitState/... on the
  coexist-sync-run repository, staging repository methods, and a new
  coexistImportService holding the historical-import transaction
- contact/tag/sequence flow steps, inbox labels, templates, message
  status and received-message activity tracking routed through
  contactService, tagService, contactSequenceService,
  conversationService, inboxService and the integration services
- sequenceDispatchUtils gains findRunning/markCompleted/markCanceled/
  markFailed; new ai-embedding, integration-lookup and import
  repositories; lib/db.ts keeps its exported names and signatures

Deliberate behavior changes (recorded in the PR): stepBlockContact now
goes through contactService.block (emits + invalidates), setFlowFlags
invalidates the contact cache, process-ai-file enqueues only the ids it
inserted, send-flow-direct and update-avatar add workspace scoping, and
the inbound/outbound activity conversation updates add workspaceId to
their WHERE.
Clears direct `db` imports from apps/builder/src/features/integration-*
across AI providers (claude/deepseek/gemini/openai), all seven channels
(telegram/tiktok/zalo/webchat/messenger/instagram/whatsapp), message
templates, smtp, and google-sheets — routing writes through packages/business
services instead, per the action | api → service → repository → db chain.

- New consolidated packages/business/src/integration-ai-provider/connect.ts
  shared by the four AI-provider services (structurally identical tables).
- New packages/business/src/{messenger,whatsapp}-message-template and
  whatsapp-flow services extracted from what were misnamed app-layer
  "service" files doing Meta/WhatsApp API sync merged with raw DB writes.
- Existing per-channel services (telegram/tiktok/zalo/webchat/messenger/
  instagram/whatsapp/google-sheet/smtp) gained connect/disconnect/update
  methods; app-layer actions keep external API calls, quota checks, and
  redirect() orchestration.
- Fixed pre-existing test mocks broken by the new import graph (missing
  service exports, @chatbotx.io/database/partials pulled in unmocked).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

fix: wip reason fix
…ndpoints

Adds GET /v1/integrations/{id}, GET /v1/integrations/status/token-errors, and
GET/PUT/DELETE /v1/integrations/ai/{provider} (claude/deepseek/gemini/openai)
to the existing `integrations` workspace-token scope, building on the
consolidated AI-provider services from the prior commit.

- Splits apps/builder/src/features/integrations/api/public.ts into
  public/{crud,ai}.ts, matching the contacts/ecommerce public API convention.
- The AI-provider response never includes the encrypted `auth` field — only
  a `hasApiKey` boolean — enforced by an explicit assertion in
  integrations-public-api.test.ts.
- integrations-public-scope.test.ts verifies every submodule registers under
  the `integrations` scope.
- Regenerates the committed public-spec-operations snapshot for the 6 new
  operations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…access methods

Rename service methods that are not (or cannot be) workspace-scoped with an
explicit `*Unscoped`/intent-revealing suffix (tag/contact-to-tag joins with
no workspaceId column, coexist run claim/reclaim), and scope Messenger/
WhatsApp template lookups by workspaceId through the integration relation
instead of leaving them keyed only by template id. Also verify the AI
provider API key and invalidate the AI integration cache on connect/
disconnect in the public integrations API.
@realcodesiman
realcodesiman force-pushed the refactor/data-access-worker-integration branch from 4a27c1a to b72e403 Compare September 9, 2026 00:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Refactor or performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant